package yartiss.gui.main;

import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import yartiss.engine.simulation.IEnergyConsumptionProfile;
import yartiss.engine.simulation.IEnergyProfile;
import yartiss.engine.simulation.ISchedulingPolicy;
import yartiss.engine.simulation.Processor;
import yartiss.engine.simulation.energy.profiles.consumption.ConsumptionProfileFactory;
import yartiss.engine.simulation.events.EventGenerator;
import yartiss.engine.simulation.scheduling.policies.AbstractMultiProcSchedulingPolicy;
import yartiss.engine.simulation.scheduling.policies.SchedulingPolicyFactory;
import yartiss.engine.simulation.system.ITask;
import yartiss.engine.simulation.system.ITaskSet;
import yartiss.engine.simulation.system.taskset.AbstractTaskSet;

public class MainDemo {
	public static void main(String[] args) {
		SchedulingPolicyFactory.registerPolicy(new LLF());
		ConsumptionProfileFactory.registerConsumptionProfile(new LogConsumption());
		DesktopMain main  = new DesktopMain();
		main.setVisible(true);
	}
}

class LogConsumption implements IEnergyConsumptionProfile {
	@Override public String getName() {return "log";}
	@Override public List<Double> getParameters() {return null;}
	@Override public void setParameters(List<Double> params) {}
	
	@Override public long getConsumed(long wcet, long wcee, long romainingTimeCost,	long duration) {
		double a = wcet - romainingTimeCost;
		double b = a + duration;
		if(b > wcet) b = wcet;
		if( (b-a) <= 0 )return 0; 
		long result = (long) Math.log(b/a);
		if(result > wcee )result = wcee;
		return result;
	}

	@Override	public IEnergyConsumptionProfile cloneProfile() {
		return new LogConsumption();
	}
}

class LLF extends AbstractMultiProcSchedulingPolicy{
	@Override public String getPolicyName() {
		return "LLF";
	}

	@Override public ITaskSet createTaskSet() {
		return new AbstractTaskSet(new Comparator<ITask>() {
			@Override	public int compare(ITask t1, ITask t2) {
				long laxity1  = t1.getDeadline() - t1.getRemainingCost();
				long laxity2 = t2.getDeadline() - t2.getRemainingCost();
				int cmp =  (int) (laxity1 - laxity2);
				if(cmp==0)
					return (int) (t1.getPriority() - t2.getPriority());
				return cmp;
			}
		}) {
			@Override	public SortedSet<ITask> getActiveTasks(long date) {
				SortedSet<ITask> activeTasks = new TreeSet<ITask>(comparator);
				for (ITask t : this)
					if (t.isActive())
						activeTasks.add(t);
				return activeTasks;
			}
		};
			
			
	}

	@Override	public Processor[] chooseNextTasks(Processor[] processors,	ITaskSet taskSet, IEnergyProfile energyProfile, long date,	EventGenerator evGen) {
		int i=0;
		for (ITask task : taskSet.getActiveTasks(date)) {
			if(i<processors.length){
				long hlcet = energyProfile.howLongCanExecute(task);
				if (hlcet <= 0) {
					evGen.generateEvent("energy_failure", task, date, null);
					processors[i].setNextTask(null);
				}
				else {
					evGen.generateEvent("check_energy_state", task, date + 1, null);
					processors[i].setNextTask(task);
				}
			}
			i++;
		}
		for(;i<processors.length; i++){
			processors[i].setNextTask(null);
		}
		return processors;
	}

	@Override	public ISchedulingPolicy newInstance() {
		return new LLF();
	}
}
